//
//  UIImage+MSImage.m
//  PeopleForTheFirstMall
//
//  Created by iOS on 2017/11/8.
//  Copyright © 2017年 MS. All rights reserved.
//

#import "UIImage+MSImage.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreImage/CoreImage.h>
#import <QuartzCore/QuartzCore.h>
#import <Accelerate/Accelerate.h>

@implementation UIImage (MSImage)

/** 改变图片颜色 */
-(UIImage*)imageChangeColor:(UIColor*)color
{
    //获取画布
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    //画笔沾取颜色
    [color setFill];
    
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);
    //绘制一次
    [self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];
    //再绘制一次
    [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];
    //获取图片
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}
+ (UIImage *)ms_imageWithColor:(UIColor *)color
                          size:(CGSize)size
{
    CGRect frame = CGRectMake(0,
                              0,
                              size.width,
                              size.height);
    
    UIGraphicsBeginImageContext(frame.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, frame);
    // 图片缩放，是非线程安全的
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    //关闭上下文
    UIGraphicsEndImageContext();
    return theImage;
}

+ (UIImage *)ms_imageWithColor:(UIColor *)color
                          size:(CGSize)size
                  cornerRadius:(CGFloat)cornerRadius
{
    CGRect frame = CGRectMake(0,
                              0,
                              size.width,
                              size.height);
    // 开始一个Image的上下文
    UIGraphicsBeginImageContext(frame.size);
    // 添加圆角
    [[UIBezierPath bezierPathWithRoundedRect:frame
                                cornerRadius:cornerRadius] addClip];
    // 绘制图片
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, frame);
    // 图片缩放，是非线程安全的
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    //关闭上下文
    UIGraphicsEndImageContext();
    return image;
}

+ (UIImage *)ms_imageForString:(NSString *)string
                     imageSize:(CGFloat)Imagesize
                 logoImageSize:(CGFloat)waterImagesize
{
    // 1.创建过滤器
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    // 2.恢复滤镜默认设置
    [filter setDefaults];
    // 3.设置数据(通过滤镜对象的KVC)
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    [filter setValue:data forKey:@"inputMessage"];//通过kvo方式给一个字符串，生成二维码
    // 4.设置二维码的纠错水平，越高纠错水平越高，可以污损的范围越大(L　: 7%, M　: 15%, Q　: 25%, H　: 30%)
    [filter setValue:@"H" forKey:@"inputCorrectionLevel"];
    // 5.生成二维码(前提建立一个UIIMageView对象存放图片),但是图片 发现有的小 (27,27),我们需要放大
    CIImage *outPutImage = [filter outputImage];
    // 不处理图片模糊,故而调用下面的信息
    return [[self alloc] ms_createNonInterpolatedUIImageFormCIImage:outPutImage
                                                           withSize:Imagesize
                                                     waterImageSize:waterImagesize];
}

/** 生成高清二维码 */
- (UIImage *)ms_createNonInterpolatedUIImageFormCIImage:(CIImage *)image
                                               withSize:(CGFloat) size
                                         waterImageSize:(CGFloat)waterImagesize
{
    CGRect extent = CGRectIntegral(image.extent);
    CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
    
    //1.创建bitmap;
    size_t width = CGRectGetWidth(extent) * scale;
    size_t height = CGRectGetHeight(extent) * scale;
    //2.创建一个DeviceGray颜色空间
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
    //CGBitmapContextCreate(void * _Nullable data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, CGColorSpaceRef  _Nullable space,
    //width：图片宽度像素
    //height：图片高度像素
    //bitsPerComponent：每个颜色的比特值，例如在rgba-32模式下为8
    //bitmapInfo：指定的位图应该包含一个alpha通道。
    CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
    CIContext *context = [CIContext contextWithOptions:nil];
    //3.创建CoreGraphics image
    CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
    CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
    CGContextScaleCTM(bitmapRef, scale, scale);
    CGContextDrawImage(bitmapRef, extent, bitmapImage);
    
    //4.保存bitmap到图片
    CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
    CGContextRelease(bitmapRef);
    CGImageRelease(bitmapImage);
    
    //原图
    UIImage *outputImage = [UIImage imageWithCGImage:scaledImage];
    if (waterImagesize > 0)
    {
        //给二维码加 logo 图
        UIGraphicsBeginImageContextWithOptions(outputImage.size, NO, [[UIScreen mainScreen] scale]);
        [outputImage drawInRect:CGRectMake(0,0 , width, height)];
        //logo图
        UIImage *waterimage = [UIImage imageNamed:@"Logo"];
        //把logo图画到生成的二维码图片上，注意尺寸不要太大（最大不超过二维码图片的%30），太大会造成扫不出来
        [waterimage drawInRect:CGRectMake((width-waterImagesize)/2.0, (height-waterImagesize)/2.0, waterImagesize, waterImagesize)];
        UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return newPic;
    }
    else
    {
        return outputImage;
    }
}
/** 根据view生成图片（opaque 表示是否是非透明的。如果需要显示半透明效果，需要传NO，否则传YES.） */
+ (UIImage *)ms_imageWithView:(UIView *)view
                     withSize:(CGSize)size
                       opaque:(BOOL)opaque
{
    if (CGSizeEqualToSize(size, CGSizeZero)) size = CGSizeMake(1, 1);
    // 下面方法，第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果，需要传NO，否则传YES。第三个参数就是屏幕密度了，关键就是第三个参数 [UIScreen mainScreen].scale。
    UIGraphicsBeginImageContextWithOptions(size, opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}
- (NSString *)ms_getQRCodeInfo
{
    // 创建一个CIImage对象
    CIImage *ciImage = [CIImage imageWithData:UIImagePNGRepresentation(self)];
    // 上下文
    CIContext *context = [CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer : @(YES)}];
    // 二维码识别,初始化扫描仪，设置设别类型和识别质量
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode
                                              context:context
                                              options:@{CIDetectorAccuracy : CIDetectorAccuracyHigh}];
    //    detector
    // 注意这里的CIDetectorTypeQRCode
    // 扫描获取的特征组
    NSArray *features = [detector featuresInImage:ciImage];
    // 获取扫描结果
    CIQRCodeFeature *feature = [features firstObject];
    NSString *scannedResult = feature.messageString;
    
    return scannedResult;
}

- (UIImage *)ms_compressForWidth:(CGFloat)defineWidth
{
    UIImage *newImage = nil;
    CGSize imageSize = self.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = defineWidth;
    CGFloat targetHeight = height / (width / targetWidth);
    CGSize size = CGSizeMake(targetWidth, targetHeight);
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
    
    if(CGSizeEqualToSize(imageSize, size) == NO){
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;
        if(widthFactor > heightFactor){
            scaleFactor = widthFactor;
        }
        else{
            scaleFactor = heightFactor;
        }
        scaledWidth = width * scaleFactor;
        scaledHeight = height * scaleFactor;
        if(widthFactor > heightFactor){
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        }else if(widthFactor < heightFactor){
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }
    UIGraphicsBeginImageContext(size);
    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width = scaledWidth;
    thumbnailRect.size.height = scaledHeight;
    
    [self drawInRect:thumbnailRect];
    
    newImage = UIGraphicsGetImageFromCurrentImageContext();
    if(newImage == nil){
        NSLog(@"scale image fail");
    }
    
    UIGraphicsEndImageContext();
    return newImage;
}
/** 修改图片大小 */
- (UIImage *)ms_scaleToSize:(CGSize)newsize
{
    if (CGSizeEqualToSize(self.size, newsize)) return self;
    /**
     创建一个bitmap的context
     并把它设置成为当前正在使用的context
     */
    UIGraphicsBeginImageContextWithOptions(newsize, NO, [[UIScreen mainScreen] scale]);
    // 绘制改变大小的图片
    [self drawInRect:CGRectMake(0, 0, newsize.width, newsize.height)];
    // 从当前context中创建一个改变大小后的图片
    UIImage * scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    // 使当前的context出堆栈
    UIGraphicsEndImageContext();
    // 返回新的改变大小后的图片
    return scaledImage;
}
/** 旋转图片 */
-(UIImage*)ms_rotateImageWithDegree:(CGFloat)degree
{
    //将image转化成context
    //获取图片像素的宽和高
    size_t width =self.size.width*self.scale;
    size_t height =self.size.height*self.scale;
    //颜色通道为8因为0-255经过了8个颜色通道的变化
    //每一行图片的字节数因为我们采用的是ARGB/RGBA所以字节数为width * 4
    size_t bytesPerRow =width *4;
    //图片的透明度通道
    CGImageAlphaInfo info =kCGImageAlphaPremultipliedFirst;
    //配置context的参数:
    CGContextRef context =CGBitmapContextCreate(nil, width, height,8, bytesPerRow,CGColorSpaceCreateDeviceRGB(),kCGBitmapByteOrderDefault|info);
    if(!context)
    {
        return nil;
    }
    //将图片渲染到图形上下文中
    CGContextDrawImage(context,CGRectMake(0,0, width, height),self.CGImage);
    uint8_t* data = (uint8_t*)CGBitmapContextGetData(context);
    //旋转欠的数据
    vImage_Buffer src = { data,height,width,bytesPerRow};
    //旋转后的数据
    vImage_Buffer dest= { data,height,width,bytesPerRow};
    //背景颜色
    Pixel_8888 backColor = {0,0,0,0};
    //填充颜色
    vImage_Flags flags = kvImageBackgroundColorFill;
    //旋转context
    vImageRotate_ARGB8888(&src, &dest,nil, degree *M_PI/180.f, backColor, flags);
    //将conetxt转换成image
    CGImageRef imageRef =CGBitmapContextCreateImage(context);
    UIImage* rotateImage =[UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
    return rotateImage;
}
/**
 压缩图片，优先采用质量压缩，如过还是大于自定大小，则进行大小压缩直到指定大小
 
 @param maxLenght 最大字节
 @return 压缩后的data
 */
- (NSData *)ms_compressToMaxLength:(NSInteger)maxLenght
{
    CGFloat compressionQuality = 1;
    NSData *data = UIImagePNGRepresentation(self);
    
    if (data.length <= maxLenght) return data;
    
    // 1.compress by quality
    CGFloat max = 1;
    CGFloat min = 0;
    for (int i = 0; i < 6; i++)
    {
        compressionQuality = (max + min) / 2;
        data = UIImageJPEGRepresentation(self, compressionQuality);
        
        if (data.length < maxLenght * 0.9)
        {
            min = compressionQuality;
        }
        else if (data.length > maxLenght)
        {
            max = compressionQuality;
        }
        else
        {
            break;
        }
    }
    
    if (data.length <= maxLenght) return data;
    
    // 2.compress by size
    UIImage *resultImage = [UIImage imageWithData:data];
    NSUInteger lastDataLength = 0;
    
    while (data.length > maxLenght && data.length != lastDataLength)
    {
        lastDataLength = data.length;
        CGFloat ratio = (CGFloat)maxLenght / data.length;
        // Use NSUInteger to prevent white blank
        CGSize size = CGSizeMake((NSUInteger)(resultImage.size.width * sqrt(ratio)),
                                 (NSUInteger)(resultImage.size.height * sqrt(ratio)));
        
        // Use image to draw (drawInRect:), image is larger but more compression time
        UIGraphicsBeginImageContext(size);
        [resultImage drawInRect:CGRectMake(0,
                                           0,
                                           size.width,
                                           size.height)];
        resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        data = UIImageJPEGRepresentation(resultImage, compressionQuality);
    }
    
    return data;
}

+ (UIImage *)ms_imageWithColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0, 0, 1, 1);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return theImage;
}

+ (UIImage *)ms_imageFromColors:(NSArray<UIColor *> *)colors
                   gradientType:(GradientType)gradientType
                        imgSize:(CGSize)imgSize
{
    NSMutableArray *ar = [NSMutableArray array];
    for(UIColor *c in colors)
    {
        [ar addObject:(id)c.CGColor];
    }
    UIGraphicsBeginImageContextWithOptions(imgSize, NO, 1);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)ar, NULL);
    CGPoint start;
    CGPoint end;
    
    switch (gradientType)
    {
        case GradientTypeTopToBottom:
            start = CGPointMake(0.0, 0.0);
            end = CGPointMake(0.0, imgSize.height);
            break;
        case GradientTypeLeftToRight:
            start = CGPointMake(0.0, 0.0);
            end = CGPointMake(imgSize.width, 0.0);
            break;
        case GradientTypeUpleftToLowright:
            start = CGPointMake(0.0, 0.0);
            end = CGPointMake(imgSize.width, imgSize.height);
            break;
        case GradientTypeUprightToLowleft:
            start = CGPointMake(imgSize.width, 0.0);
            end = CGPointMake(0.0, imgSize.height);
            break;
        default:
            break;
    }
    
    CGContextDrawLinearGradient(context, gradient, start, end,kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    CGGradientRelease(gradient);
    CGContextRestoreGState(context);
    CGColorSpaceRelease(colorSpace);
    UIGraphicsEndImageContext();
    return image;
}


/** 获取视频的第一帧截图, 返回UIImage */
+ (UIImage *)ms_getVideoPreViewImageWithPath:(NSURL *)videoPath
{
    NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
                                                     forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoPath
                                                options:opts];
    NSParameterAssert(asset);//断言
    AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
    gen.appliesPreferredTrackTransform = YES;
    gen.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
    gen.requestedTimeToleranceAfter = kCMTimeZero;
    gen.requestedTimeToleranceBefore = kCMTimeZero;
    // 处理视频内容事常见的时间刻度为600，这是大部分视频帧率24fps、25fps、30fps的公倍数。音频数据常见的时间刻度就是采样率，譬如44 100(44.1kHZ)或48 000(48kHZ)。
    CMTime time = CMTimeMakeWithSeconds(0.2, 600); // 防止视频第一帧黑屏 获取0.2秒的截图, 600fps
    NSError *error = nil;
    CMTime actualTime;
    CGImageRef image = [gen copyCGImageAtTime:time
                                   actualTime:&actualTime
                                        error:&error];
    UIImage *img = [[UIImage alloc] initWithCGImage:image];
    return img;
}

- (NSString *)ms_imageDataSize
{
    NSData *data = UIImagePNGRepresentation(self);
    double length = data.length * 1.0;
    
    NSArray *typeArray = @[@"bytes",@"KB",@"MB",@"GB",@"TB",@"PB", @"EB",@"ZB",@"YB"];
    int idx = 0;
    while (length > 1024)
    {
        length /= 1024.0;
        idx++;
    }
    
    return [NSString stringWithFormat:@"%.3f%@", length, typeArray[idx]];
}

@end
